#ifndef _CTREEBOX_H_
#define _CTREEBOX_H_

#include <buola/widgets/ctreewidget.h>
#include <buola/gui/dnd/cdroptarget.h>

#include <buola/utility/usignal.h>
#include <buola/utility/uevent.h>


namespace buola { namespace gui {

class CTreeBox : public CTreeWidget,public CDropTarget
{
public:
    enum
    {
        //renderers
        STYLE_TREE=             0x00000100,
        STYLE_RENDERER=         0x00000f00,
        //view style
        STYLE_NOICON=           0x00001000,
        STYLE_NOTEXT=           0x00002000,
        STYLE_HORIZONTAL=       0x00004000,
        STYLE_HIERARCHYLINES=   0x00008000,
        STYLE_NORULER=          0x00010000,
        STYLE_MULTILINE=        0x00020000,
        STYLE_ALIGNCENTER=      0x00040000,
        STYLE_ALIGNRIGHT=       0x00080000,
        STYLE_GROUPS=           0x00100000,
        STYLE_INVERTTEXT=       0x00200000,
        STYLE_VIEW=             0x003fff00,
        //function style
        STYLE_DRAGNDROP=        0x00400000,
        STYLE_EDITABLE=         0x00800000,
        //selection style
        STYLE_SINGLE=           0x00000000,
        STYLE_MULTIPLE=         0x01000000,
        STYLE_TOGGLE=           0x02000000,
        STYLE_ONECLICK=         0x04000000,
        STYLE_SELECTION=        0x07000000,
        //menu style
        STYLE_ICONMENU=         0x10000000,
        STYLE_VIEWMENU=         0x20000000,
        STYLE_USERMENU=         0x40000000,
        STYLE_MENU=             0x70000000,

        //default styles
        STYLE_TREEVIEW=         STYLE_TREE,
        STYLE_DEFAULTVIEW=      STYLE_TREE|STYLE_ICONMENU|STYLE_VIEWMENU
    };

public:
    CTreeBox();
    ~CTreeBox();

public:
    void EnsureVisible(SNode *pNode,bool pMore);

    int GetIconSize()           {   return mIconSize;   }
    void SetIconSize(int);

    bool GetAutoUpdate()        {   return mAutoUpdate; }
    void SetAutoUpdate(bool);
    void Update();

    const PScrollBar &GetVScroll()    {   return mVScroll;    }
    const PScrollBar &GetHScroll()    {   return mHScroll;    }
    
    const CPoint_d &GetScrollPos()  {   return mScrollPos;  }

    void SetEmptyText(const std::wstring&);

    void EndEditing();

    void CreateRenderer();

    SNode *GetCursorNode()  {   return mCursorNode; }

protected:
////////////// Event handling //////////////
    virtual void OnExpose(const CExposeEvent &pE);
    void OnHScroll(int pPos);
    void OnVScroll(int pPos);
    virtual void OnButtonDown(const CMouseEvent &pE);
    virtual void OnButtonUp(const CMouseEvent &pE);
    virtual void OnMouseMove(const CMouseEvent &pE);
    virtual void OnMouseWheel(const CMouseEvent &pE);

    virtual void OnFocusIn(const CFocusEvent &pE);
    virtual void OnFocusOut(const CFocusEvent &pE);
    virtual void OnChar(const CKeyEvent &pE);
    virtual void OnKeyDown(const CKeyEvent &pE);

    virtual void OnSize(const CGeometryEvent &pE);
    virtual void OnStyleChanged(TStyle);

    virtual void OnCursorChanged(SNode*);
    virtual void OnNodeSelected(SNode*);
    virtual void OnNodeExpanded(SNode*);
    virtual void OnNodeChanged(SNode*);
    virtual void OnNodeAdded(SNode*);
    virtual void OnNodeRemoved(SNode*);
    virtual void OnFieldsChanged();

    virtual void OnFillMenu(PMenu,bool) {}

    virtual void OnDropEnter(CDrop*,const CPoint_d&);
    virtual void OnDropLeave(CDrop*,const CPoint_d&);
    virtual void OnDropMove(CDrop*,const CPoint_d&);
    virtual void OnDropCancel(CDrop*,const CPoint_d&);
    virtual void OnDropDrop(CDrop*,const CPoint_d&,EDNDActions);

    virtual bool WillAccept(SNode*,CDrop*)  {   return false;   }
    virtual void OnDrop(SNode*,CDrop*,EDNDActions)   {}

public:
    USignal<void(PMenu,SNode*)> sFillMenu;
    UEvent<void(SNode*)> eDblClick;
    UEvent<void(SNode*)> eCursorChanged;
    USignal<void(SNode*)> sSelected;
    USignal<void(SNode*)> sUnselected;

protected:
/////////////// protected functions //////////////
    PScrollBar mHScroll;
    PScrollBar mVScroll;

    bool mDragging;
    bool mSelecting;
    SNode *mEditing;

    SNode *mCursorNode;

    CPoint_d mDragPoint;
    CPoint_d mLastDragPoint;

    int mIconSize;

    bool mAutoUpdate;
    PEditBox mEditBox;

    std::wstring mEmptyText;

    struct
    {
        bool mInside;
        SNode *mLast;
        bool mAccept;
    } mDropping;

    std::unique_ptr<CTBRenderer> mRenderer;
    CPoint_d mScrollPos;

/////////////////// static data ////////////////////
    friend class CTBTreeRenderer;
};

/*namespace gui*/ } /*namespace buola*/ }

#endif
